import service from "../utils/Request";
import Util from "../utils/Util";
import { execute} from "../utils/RequestUtil";
import LabEvent from "./LabEvent";
import { Local } from "../utils/StorageData";

export default {
    mixins: [LabEvent],
    data() {
        return {
            requesting: false,
            /**
             * 数据源请求过滤信息和请求体
             */
            sourceFilters: [],
            pageInfo: { page: 1, pageSize: 10, total: 0, filters: [], sorts: [] },
            dataSource: []
        }
    },
    methods: {
        /**
         * 触发指定请求
         * @param trigger           目标请求
         * @param args              参数源
         * @param body              完全自定义的请求体
         */
        dispatchRequest(trigger, args, body){
            return new Promise(resolve => {
                if (!this.element) {
                    resolve({code: 200})
                }
                const { requests } = this.element
                if (Util.isEmpty(requests) || Util.isEmpty(trigger)){
                    resolve({code: 202, msg: '未匹配到组件请求'})
                } else {
                    const request = requests.find(item => item.trigger === trigger)
                    if (!request) {
                        resolve({code: 203,msg: '未匹配到组件目标请求'})
                        return
                    }
                    if (!Util.isEmpty(request.cacheKey) && !this.labDesign.switch) {
                        const cacheData = Local.get(request.cacheKey)
                        if (!Util.isEmpty(cacheData)) {
                            resolve(cacheData)
                            return;
                        }
                        this.$store.dispatch('requestQueue/setQueue', { cacheKey: request.cacheKey, resolve: resolve });
                        const list = this.$store.state.requestQueue.queue[request.cacheKey]
                        if (list.length > 1) {
                            console.info('缓存请求')
                            return;
                        }
                    }
                    this.requesting = true
                    this.dispatchEvent('requestBefore', { trigger, args, body, request })
                        .then(before => {
                            if (before.code > 200) {
                                this.execRequest(request, args, body)
                                    .then(res => {
                                        this.dispatchEvent('requestAfter', { trigger, args, body, request, res })
                                            .then(() => {
                                                if (!Util.isEmpty(request.cacheKey) && !this.labDesign.switch) {
                                                    Local.set(request.cacheKey, res)
                                                    const list = this.$store.state.requestQueue.queue[request.cacheKey]
                                                    list.forEach(queue => {
                                                        queue.resolve(res)
                                                    })
                                                    this.$store.dispatch('requestQueue/clearQueue', { cacheKey: request.cacheKey });
                                                } else {
                                                    resolve(res)
                                                }
                                                setTimeout(() => {
                                                    this.requesting = false
                                                }, 100)
                                            })
                                    })
                            } else {
                                this.requesting = false
                            }
                        })
                }
            })
        },
        /**
         * 查找指定请求
         * @param trigger   请求
         */
        findRequest(trigger) {
            const { requests } = this.element
            if (Util.isEmpty(requests) || Util.isEmpty(trigger)){
                return undefined
            } else {
                const request = requests.find(item => item.trigger === trigger)
                if (!request) {
                    return undefined
                }
                return Util.copy(request)
            }
        },
        /**
         * 获取指定类型值
         * @param value     值
         * @param type      类型
         * @returns {*|string|Array|number}  指定类型值
         */
        toTypeValue(value, type){
            if (type === 'Object') {
                return Util.toObj(value)
            } else if (type === 'Array') {
                return Util.toArray(value)
            } else if (type === 'Number') {
                return Util.toNumber(value)
            }  else {
                return Util.toTextString(value)
            }
        },
        /**
         * 获取请求参数
         * @param param         参数定义
         * @param modelData     参数对
         * @returns {*|string|Array|number}  参数值
         */
        getParamValue(param, modelData){
            let value = param.value
            if (!Util.isEmpty(param.mapper) && !Util.isEmpty(modelData)) {
                const modelVal = Util.callPropValue(modelData, param.mapper || param.prop)
                if (!Util.isEmpty(modelVal)) {
                    value = modelVal
                }
            }
            return this.toTypeValue(value, param.type)
        },
        /**
         * {
         *     requestType: 'GET|PUT|POST|DELETE',
         *     requestUrl: '请求地址',
         *     resultProp: '结果属性',
         *     params: [
         *         {
         *             prop: '属性',
         *             mapper: '取值属性',
         *             location: 'path|query|header|body,参数位置',
         *             type: 'Object|Array|Number|String，值类型'
         *             value: '默认值',
         *             op: '过滤操作'
         *         }
         *     ],
         *     filters: [
         *         {
         *             field: '过滤字段',
         *             op: '过滤操作',
         *             value: '过滤值'
         *         }
         *     ]
         * }
         * 执行请求
         * @param request           请求定义
         * @param modelData         参数集合
         * @param body              完全自定义请求体
         * @param test              请求测试
         * @returns {Promise<unknown>}  请求结果
         */
        execRequest(request, modelData, body, test){
            return new Promise((resolve) => {
                if (this.labDesign.switch && !test) {
                    resolve({code: 200,msg:'设计模式不请求'})
                    return
                }
                if (Util.isEmpty(request.requestUrl)){
                    resolve({code: 500,msg:'请填写请求地址'})
                    return
                }
                if (Util.isEmpty(request.requestType)){
                    resolve({code: 500,msg:'请选择请求类型'})
                    return
                }
                const options = {
                    method: request.requestType,
                    url: this.getUrl(request, modelData),
                    timeout: request.timeOut || 5000,
                    headers: this.getHeader(request, modelData),
                    data: Util.isEmpty(body) ? this.getBody(request, modelData): body
                }
                if (!Util.isEmpty(options.data)) {
                    this.initBody(request, modelData, options.data)
                }
                if (request.checkToken) {
                    execute(options, request.resultProp)
                        .then(res => {
                            resolve(res)
                        })
                } else {
                    service(options).then(res => {
                        if (Util.isEmpty(request.resultProp)) {
                            resolve(res)
                        } else {
                            if (res.code === 200) {
                                resolve(Util.callPropValue(res, request.resultProp))
                            } else {
                                resolve(res)
                            }
                        }
                    }).catch(res => {
                        resolve(res)
                    })
                }
            })
        },
        /**
         * 确认执行事件请求
         * @param config        确认弹窗配置
         * @param trigger       请求点
         * @param modelData     参数
         * @param body          请求体
         * @return {Promise<unknown>}
         */
        confirmDispatch(config, trigger, modelData, body) {
            return new Promise(resolve => {
                config = Object.assign({}, {
                    title: '提示',
                    content: '该操作影响的数据将不可恢复, 是否继续?',
                    sure: '确定',
                    cancel: '取消',
                    type: 'warning'
                }, config || {})

                this.$confirm(config.content, config.title, {
                    confirmButtonText: config.sure,
                    cancelButtonText: config.cancel,
                    type: config.type
                }).then(() => {
                    this.dispatchRequest(trigger, modelData, body)
                        .then(res => {
                            resolve(res)
                        })
                }).catch(() => {
                    resolve({ code: 100 })
                })
            })
        },
        /**
         * 确认执行请求
         * @param config        确认弹窗配置
         * @param request       请求
         * @param modelData     参数
         * @param body          请求体
         * @return {Promise<unknown>}
         */
        confirmExecute(config, request, modelData, body){
            return new Promise(resolve => {
                config = Object.assign({}, {
                    title: '提示',
                    content: '该操作影响的数据将不可恢复, 是否继续?',
                    sure: '确定',
                    cancel: '取消',
                    type: 'warning'
                }, config || {})

                this.$confirm(config.content, config.title, {
                    confirmButtonText: config.sure,
                    cancelButtonText: config.cancel,
                    type: config.type
                }).then(() => {
                    this.execRequest(request, modelData, body)
                        .then(res => {
                            resolve(res)
                        })
                }).catch(() => {
                    resolve({ code: 100 })
                })
            })
        },
        getUrl(request, modelData){
            const { params } =  request
            let url = request.requestUrl
            if (!Util.isEmpty(params)) {
                const pathArgs = params.filter(item => item.location === 'path')
                const queryArgs = params.filter(item => item.location === 'query')
                if (!Util.isEmpty(pathArgs)) {
                    if (url.endsWith('/')) {
                        url = url.substring(0, url.length - 1)
                    }
                    pathArgs.forEach(item => {
                        const value = this.getParamValue(item, modelData)
                        url += `/${value}`
                    })
                }
                if (!Util.isEmpty(queryArgs)) {
                    queryArgs.forEach(item => {
                        const value = this.getParamValue(item, modelData)
                        if (url.includes('?')) {
                            url += `&${item.prop}=${value}`
                        } else {
                            url += `?${item.prop}=${value}`
                        }
                    })
                }
            }
            if (url.includes('?')) {
                url += '&appId=' + this.appInfo.appId
            } else {
                url += '?appId=' + this.appInfo.appId
            }
            return url
        },
        getHeader(request, modelData) {
            const { params } =  request
            const header = {}
            if (!Util.isEmpty(params)) {
                const headerArgs = params.filter(item => item.location === 'header')
                headerArgs.forEach(item => {
                    Reflect.set(header, item.prop, this.getParamValue(item, modelData))
                })
            }
            return header
        },
        /**
         * 获取请求定义中的请求体
         * @param request  请求定义对象
         * @param modelData 参数
         */
        getBody(request, modelData){
            const body = {}
            const { params } =  request
            if (!Util.isEmpty(params)) {
                const bodyArgs = params.filter(item => item.location === 'body')
                if (!Util.isEmpty(bodyArgs)) {
                    bodyArgs.forEach(item => {
                        Reflect.set(body, item.prop, this.getParamValue(item, modelData))
                    })
                }

            }
            return body
        },
        /**
         * 查询体处理
         */
        initBody(request, modelData, body){
            const keys = Object.keys(body)
            if (Util.isEmpty(request.bodyFilter)) {
                if (keys.includes('filters')) {
                    request.bodyFilter = 'filters'
                } else if (keys.includes('params')) {
                    request.bodyFilter = 'params'
                }
            }
            // 过滤参数
            if (!Util.isEmpty(request.bodyFilter)) {
                const filters = Reflect.get(body, request.bodyFilter) || []
                const { params } =  request
                if (!Util.isEmpty(params)) {
                    const filterArgs = params.filter(item => item.location === 'filter')
                    if (!Util.isEmpty(filterArgs)) {
                        filterArgs.forEach(item => {
                            const copyItem = Util.copy(item)
                            copyItem.value = this.getParamValue(copyItem, modelData)
                            if (!Util.isEmpty(copyItem.value)) {
                                this.addFilter({ field: copyItem.prop, op: copyItem.op || '=', value: copyItem.value }, filters)
                            }
                        })
                    }
                }
                if (!Util.isEmpty(this.sourceFilters)) {
                    this.sourceFilters.forEach(item => {
                        this.addFilter(item, filters)
                    })
                }
                Reflect.set(body, request.bodyFilter, filters)
                this.pageInfo.filters = filters
            }
            // 分页
            if (keys.includes('page')) {
                body.page = this.pageInfo.page
            }
            if (keys.includes('pageSize')) {
                body.pageSize = this.pageInfo.pageSize
            }
        },
        /**
         * 追加过滤参数
         * @param item        追加参数
         * @param filters     源过滤参数集合   未指定时默认为数据源的
         */
        addFilter(item, filters) {
            if (Util.isEmpty(item) || Util.isEmpty(item.field)) {
                return
            }
            filters = filters || this.sourceFilters
            if (Util.isEmpty(filters)){
                filters.push(item)
            } else {
                const filter = filters.find(e => e.field === item.field)
                if (Util.isEmpty(filter)) {
                    filters.push(item)
                } else {
                    filter.op = item.op
                    filter.value = item.value
                }
            }
        },
        /**
         * 移除过滤参数
         * @param field     移除字段
         * @param filters   源过滤参数集合   未指定时默认为数据源的
         */
        delFilter(field, filters) {
            filters = filters || this.sourceFilters
            const index = filters.findIndex(item => item.field === field)
            if (index > -1) {
                filters.splice(index, 1)
            }
        }
    }
}
